package com.daervin.svc.manager;

import com.daervin.svc.common.constants.SourceEnum;
import com.daervin.svc.common.constants.StockOpTypeEnum;
import com.daervin.svc.common.dto.*;
import com.daervin.svc.common.exception.CommonException;
import com.daervin.svc.common.exception.ErrorCode;
import com.daervin.svc.common.utils.BarCodeUtils;
import com.daervin.svc.common.utils.DateTimeUtils;
import com.daervin.svc.dal.WhProductMapper;
import com.daervin.svc.dal.model.WhProductDO;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * Created by daervin on 2023/8/18
 */
@Component
public class ProductManager {
    @Resource
    private WhProductMapper whProductMapper;
    @Resource
    private CategoryManager categoryManager;
    @Resource
    private SupplierManager supplierManager;
    @Resource
    private StockManager stockManager;

    public boolean addOrUpdate(WhProductDTO productDTO) {
        WhCategoryDTO categoryDTO = categoryManager.match(productDTO.getCategoryId());
        if (categoryDTO == null) {
            throw new CommonException(ErrorCode.ERROR_PARAM, "品类不存在");
        }
        WhSupplierDTO supplierDTO = supplierManager.match(productDTO.getSupplierId());
        if (supplierDTO == null) {
            throw new CommonException(ErrorCode.ERROR_PARAM, "供应商不存在");
        }

        WhProductDO record = new WhProductDO();
        record.setId(productDTO.getId());
        record.setName(productDTO.getName());
        record.setImg(productDTO.getImg());
        record.setCategoryId(categoryDTO.getId());
        record.setSupplierId(supplierDTO.getId());
        record.setBarCode(productDTO.getBarCode());
        record.setPrice(productDTO.getPrice());
        record.setShowPrice(productDTO.getShowPrice());

        if (!StringUtils.isEmpty(productDTO.getBarCode())) {
            byte[] bytes = BarCodeUtils.generateBarCode128(productDTO.getBarCode(), 3D, 10D, 3d, true, null);
            String base64Str = Base64.getEncoder().encodeToString(bytes);
            record.setBarCodeSrc(base64Str);
        }

        record.setExt(productDTO.getExt());
        record.setUpdateTime(new Date());

        if (record.getId() == null || record.getId() <= 0) {
            whProductMapper.insertSelective(record);
            stockManager.initStockByProductId(record.getId());
            return true;
        }
        whProductMapper.updateByPrimaryKeySelective(record);
        return true;
    }

    public boolean updateProductStock(UpdateProductStockDTO req) {
        WhProductDTO productDTO = getDetail(req.getProductId());
        if (productDTO == null) {
            throw new CommonException(ErrorCode.ERROR_PARAM, "商品不存在");
        }
        StockOpTypeEnum opTypeEnum = StockOpTypeEnum.valOf(req.getOpType());
        return stockManager.updateStockByProductId(req.getProductId(), req.getStock(), opTypeEnum, SourceEnum.MANAGER);
    }

    public WhProductDTO getDetail(Long productId) {
        Map<Long, WhSupplierDTO> supplierMap = supplierManager.getSupplierMap();
        Map<Long, WhCategoryDTO> categoryMap = categoryManager.getCategoryMap();

        WhProductDO productDO = whProductMapper.selectByPrimaryKey(productId);
        int stock = stockManager.getStockByProductId(productId);
        return covert(productDO, stock, supplierMap, categoryMap, true);
    }

    public PageResultDTO<WhProductDTO> getByPage(SearchProductDTO req) {
        PageResultDTO<WhProductDTO> result = new PageResultDTO<>();
        int totalCount = whProductMapper.selectCount(req);
        result.setTotalCount(totalCount);
        result.setCurrPage(req.getPageNo());
        result.setPageCount(0);
        if (totalCount == 0) {
            return result;
        }
        result.setPageCount(totalCount % req.getPageSize() == 0 ? totalCount / req.getPageSize() : totalCount / req.getPageSize() + 1);
        int offset = (req.getPageNo() - 1) * req.getPageSize();
        req.setOffset(offset);
        List<WhProductDO> list = whProductMapper.selectList(req);
        Map<Long, WhSupplierDTO> supplierMap = supplierManager.getSupplierMap();
        Map<Long, WhCategoryDTO> categoryMap = categoryManager.getCategoryMap();
        List<WhProductDTO> products = new ArrayList<>();
        list.stream().forEach(it -> {
            WhProductDTO productDO = covert(it, 0, supplierMap, categoryMap, req.getHasBarCode());
            if (productDO != null) {
                products.add(productDO);
            }
        });
        result.setResults(products);
        return result;
    }

    private WhProductDTO covert(WhProductDO productDO, int stock, Map<Long, WhSupplierDTO> supplierMap, Map<Long, WhCategoryDTO> categoryMap, boolean hasBarCode) {
        if (productDO == null) {
            return null;
        }
        WhProductDTO productDTO = new WhProductDTO();
        productDTO.setId(productDO.getId());
        productDTO.setName(productDO.getName());
        productDTO.setImg(productDO.getImg());
        productDTO.setPrice(productDO.getPrice());
        productDTO.setShowPrice(productDO.getShowPrice());
        productDTO.setStock(stock);
        WhCategoryDTO categoryInfo = categoryMap.getOrDefault(productDO.getCategoryId(), new WhCategoryDTO(0L, "未知"));
        productDTO.setCategoryInfo(categoryInfo);
        productDTO.setCategoryId(categoryInfo.getId());

        WhSupplierDTO supplierInfo = supplierMap.getOrDefault(productDO.getSupplierId(), new WhSupplierDTO(0L, "未知"));
        productDTO.setSupplierInfo(supplierInfo);
        productDTO.setSupplierId(supplierInfo.getId());

        productDTO.setBarCode(productDO.getBarCode());
        if (!StringUtils.isEmpty(productDO.getBarCode())) {
            BarCodeDTO barCodeInfo = new BarCodeDTO();
            barCodeInfo.setBarCode(productDO.getBarCode());
            barCodeInfo.setBarCodeSrc(productDO.getBarCodeSrc());
            productDTO.setBarCodeInfo(barCodeInfo);
        }
        productDTO.setExt(productDO.getExt());
        productDTO.setCreateTimeStr(DateTimeUtils.longParse(productDO.getCreateTime()));
        return productDTO;
    }

    public ResponseVO<List<ScanBarResultDTO>> uploadScanBar(ScanBarRequestDTO request) {
        if (request == null || CollectionUtils.isEmpty(request.getScanData())) {
            throw new CommonException(ErrorCode.ERROR_PARAM, "参数不正确");
        }

        List<ScanBarResultDTO> result = new ArrayList<>();

        ErrorCode errorCode = ErrorCode.SUCCESS;

        for (ScanRequestItem scanRequestItem : request.getScanData()) {
            ScanBarResultDTO resultDTO = new ScanBarResultDTO();
            resultDTO.setCode(scanRequestItem.getCode());
            resultDTO.setNum(scanRequestItem.getNum());
            if (StringUtils.isEmpty(scanRequestItem.getCode()) || scanRequestItem.getNum() <= 0) {
                resultDTO.setExt("参数不正确");
                result.add(resultDTO);
                errorCode = ErrorCode.ERROR_PARAM;
                continue;
            }
            WhProductDO whProductDO = whProductMapper.selectByCode(scanRequestItem.getCode());
            if (whProductDO == null) {
                resultDTO.setExt("请先录入商品");
                result.add(resultDTO);
                errorCode = ErrorCode.PRODUCT_NOT_FOUND;
                continue;
            }
            resultDTO.setProductId(whProductDO.getId());
            resultDTO.setProductName(whProductDO.getName());
            int stockNum = stockManager.getStockByProductId(whProductDO.getId());
            if (stockNum < scanRequestItem.getNum()) {
                resultDTO.setExt("库存不足，请检查库存");
                result.add(resultDTO);
                errorCode = ErrorCode.STOCK_NOT_ENOUGH;
                continue;
            }
            result.add(resultDTO);
        }

        if (!errorCode.equals(ErrorCode.SUCCESS)) {
            return new ResponseVO(errorCode.code, errorCode.message, result);
        }

        StockOpTypeEnum opTypeEnum = StockOpTypeEnum.OUT;
        result.stream().forEach(resultDTO -> {
            stockManager.updateStockByProductId(resultDTO.getProductId(), resultDTO.getNum(), opTypeEnum, SourceEnum.APP);
            resultDTO.setExt("成功");
        });
        return ResponseVO.success(result);
    }
}
